An application server is a software framework that delivers applications to client computers or devices. An application server facilitates software development by allowing designers and programmers to devote their time to meeting software requirements rather than dealing with the standard low-level details of providing a working system. An application server can be provided as middleware that sits between operating systems and high-level enterprise applications. An application server enables applications to intercommunicate with dependent applications, such as transaction servers, database management systems, and web servers.
An application server can host Enterprise JavaBeans (EJBs), which can be invoked by remote clients to run business methods. For example, an application server that provides banking service can host multiple EJBs, with each EJB providing a banking-related method, such as balance inquiry, cash withdrawal, deposit, etc. A single transaction can sometimes involve the invocation of one or more EJBs. For example, a balance transfer between a savings account and a checking account can be implemented with withdrawal (a first EJB) from the savings account followed by deposit (a second EJB) into the checking account. The use of EJBs simplifies application developments. With the use of EJBs, application developers can focus on the development of high-level service features, without the need to understand the low-level details about transactions and state management.
Currently, when a remote client calls remote methods on EJBs deployed on a server cluster within a transaction, a number of problems can occur. For example, suppose an EJB is deployed in a 3-node cluster with a conventional round-robin load balance policy. If the client makes three invocations to a method on this EJB within a transaction, each of the invocations will be executed by a different server node and a different transaction will be created in each server node. If the client tries to rollback the transaction, only one transaction on one of the server nodes will be rolled back.
Further, for a transaction to be successful, a number of properties need to be fulfilled. These properties include: Atomicity, Consistency, Isolation, and Durability (ACID). Atomicity refers to a property that all changes made by a transaction to a database should be made as one unit; otherwise, all changes are rolled back. Consistency refers to a property that a successful transaction transforms a database from a previous valid state to a new valid state. Isolation refers to a property that changes made by a transaction to a database are not visible to other operations until the transaction is completed. Durability refers to a property that changes made by a transaction to a database survive future system or media failures. With the existing load balance policies, there is no guarantee that a UserTransaction.begin( ) operation and any of the EJB invocations within that user transaction will be executed by the same server node. If a user transaction and the EJB invocations within that user transaction are not executed by the same server node, the ACID properties of the transaction will not be fulfilled.
Moreover, problems can arise when a remote client starts a transaction that makes remote calls on different EJBs deployed on different server nodes, and one of the nodes fails. For example, two EJBs (EJB A and EJB B) are deployed on both node 1 and node 2. A remote client starts a transaction and calls EJB A, which lands on node 1. Still within the same transaction, the remote client attempts to call EJB B and the load balance policy picks node 2. However, the call on EJB B fails. An attempt to failover to node 1 will not succeed, because transactions started in node 1 and node 2 are independent and node 2 has no knowledge of the transaction started in node 1. As a result, the failed call would not be allowed to go to a different node.